const axios = require('axios');
const ora = require('ora');
const inquirer = require('inquirer');
let { promisify } = require('util');
const path = require('path');
const fs = require('fs');
let downloadGit = require('download-git-repo');
downloadGit = promisify(downloadGit);
const { downLoadDirectory } = require('./constants');

//读取所有文件  实现模板渲染
const MetalSmith = require('metalsmith');
let { render } = require('consolidate').ejs;
render = promisify(render);

let ncp = require('ncp'); // 复制文件
ncp = promisify(ncp);

// 获取所有项目
const fetchRepoList = async () => {
    let { data } = await axios.get('https://api.github.com/orgs/zhu-cli/repos');
    return data;
}

// loading
const waitFnloading = (fn, message) => async (...args) => {
    const spinner = ora(message);
    spinner.start();
    const result = await fn(...args);
    spinner.succeed();
    return result;
}

// 抓取tag
const fetchTagList = async (repo) => {
    const { data } = await axios.get(`https://api.github.com/repos/zhu-cli/${repo}/tags`);
    return data;
}

const download = async (repo, tag) => {
    let api = `zhu-cli/${repo}`;
    if (tag) {
        api += `#${tag}`;
    }
    let dest = `${downLoadDirectory}/${repo}`;
    await downloadGit(api, dest);
    return dest;
}

module.exports = async (projectName) => {
    let repos = await waitFnloading(fetchRepoList, 'fetch template...')();
    repos = repos.map(item => item.name);
    let { repo } = await inquirer.prompt({
        name: 'repo',
        type: 'list',
        message: 'please choice a template to create project',
        choices: repos
    });
    let tags = await waitFnloading(fetchTagList, 'fetch tags ...')(repo);
    tags = tags.map(item => item.name);
    let { tag } = await inquirer.prompt({
        name: 'tag',
        type: 'list',
        message: 'please choice a tag to create project',
        choices: tags
    });
    let result = await waitFnloading(download, 'download template')(repo, tag);
    if (!fs.existsSync(path.join(result, 'ask.js'))) {
        await ncp(result, path.resolve(projectName));
    } else {
        await new Promise((resolve, reject) => {
            MetalSmith(__dirname)
                .source(result)
                .destination(path.resolve(projectName))
                .use(async (files, metal, done) => {
                    let args = require(path.join(result, 'ask.js'));
                    let obj = await inquirer.prompt(args);
                    let meta = metal.metadata();
                    Object.assign(meta, obj);
                    delete files['ask.js'];
                    done();
                })
                .use((files, metal, done) => {
                    let obj = metal.metadata();
                    Reflect.ownKeys(files).forEach(async file => {
                        if( files.includes('js') || file.includes('json')) {
                            let content = files[file].contents.toString(); // 文件内容
                            if (content.includes('<%')) {
                                content = await render(content, obj);
                                files[files].contents = Buffer.from(content); // 渲染结果
                            }
                        }
                    })
                    done();
                })
                .build((err) => {
                    if (err) {
                        reject();
                    } else {
                        resolve();
                    }
                });
        })
    }
}

